In [10]:
import numpy as np
from scipy import ndimage
import matplotlib.pyplot as plt

%matplotlib inline

plt.figure()

plt.subplot(1, 2, 1)
img = ndimage.imread('../assets/cameraman.tif', flatten=True)
plt.title("Original Image")
plt.axis('off')
plt.imshow(img, cmap="gray")

plt.subplot(1,2,2)
hist, bins = np.histogram(img.ravel(), bins=256, range=(0,255))
# a bin represents range of a single bar (so, bins[2]-bins[1] = range of the first bar)
# np.histogram computes computes the occurences of input data that fall within each bin
# if we'd like an indexed count, np.bincount() would do it.
center = (bins[:-1] + bins[1:])/2
plt.title('Orig. Img. Histogram')
plt.ylabel('occurences')
plt.xlabel('pixel values')
plt.xlim([0,256])
plt.bar(center, hist, align='center')


Out[10]:
<Container object of 256 artists>

Linear Interpolation: The idea behind linear interp is pretty simple. Suppose we have a line denoted by two points $((x1,y1), (x2,y2)), x2 > x1$ and a point in the middle $x$. Using equivalence of triangles: $$\frac{f(x)-f(x1)}{x-x1} = \frac{f(x2)-f(x1)}{x2-x1}$$

Then, solve it for $f(x)$

$$y = y1 + (y2-y1) * (\frac{x-x1}{x2-x1})$$

In [2]:
def normalize(f, n_range=(0, 255)):
    """given an img with a given range of pixel values, normalizes to fit to [0,255]
    using linear interpolation"""
    f = np.asarray(f)
    faux = np.ravel(f).astype(float)
    lower, upper = n_range
    min_val, max_val = f.min(), f.max()
    # only a single kind of value, return array of average
    
    if min_val == max_val:
        g = np.ones(f_aux.shape) * (upper+lower)/2.0
    else:
        g = lower + (upper - lower) * (faux - min_val) / (max_val - min_val)
        
    return g.reshape(f.shape).astype(f.dtype)

In [3]:
r, c = np.indices((256,256))

plt.figure(1)
plt.subplot(1,4,1)
plt.title('vertical')
plt.axis('off')
plt.imshow(normalize(np.indices((10,10))[0]), cmap="gray")

plt.subplot(1,4,2)
plt.title('horizontal')
plt.axis('off')
plt.imshow(normalize(np.indices((10,10))[1]), cmap="gray")

plt.subplot(1,4,3)
plt.title('ul')
plt.axis('off')
plt.imshow(normalize(np.indices((10,10))[1] + np.indices((10,10))[0]), cmap="gray")

plt.subplot(1,4,4)
plt.title('radial')
plt.axis('off')
plt.imshow(normalize(np.indices((10,10))[0] * np.indices((10,10))[1]), cmap="gray")

plt.figure(2)
ax = plt.subplot(1,2,1)
plt.title('Uniform x Normal Image histogram')
plt.plot(np.bincount(normalize(r).ravel()), label='Uniform', lw=2)
plt.plot(np.bincount(img.ravel().astype('uint8')), label='Normal', lw=2)
plt.legend()

ax2 = ax.twinx()
ax2.plot(np.cumsum(np.bincount(normalize(r).ravel())))
ax2.plot(np.cumsum(np.bincount(img.ravel().astype('uint8'))))


Out[3]:
[<matplotlib.lines.Line2D at 0x7f5e57d01350>]

Equalização de histograma

$$T(r) = \frac{L-1}{n}\sum\limits_{i=0}^{r}h(i), i = 0, 1 ... , L-1$$

In [4]:
plt.subplot(1,2,1)
plt.title('Original')
plt.axis('off')
plt.imshow(img, cmap="gray")

plt.subplot(1,2,2)
plt.title('Sorted')
plt.axis('off')
sorted_img = np.argsort(img.ravel())
plt.imshow(img.ravel()[sorted_img].reshape(img.shape), cmap="gray")


Out[4]:
<matplotlib.image.AxesImage at 0x7f5e57e846d0>

In [5]:
# create an empty flat array
g = np.empty((img.size,), np.uint8)
# index the array by the sorted image indices and then
# set its values with a linear space. This will, by definition
# make the distribution of pixel values uniform
g[sorted_img] = np.linspace(0, 255, img.size).astype(np.int)
# transform it into an image of the same shape as before
g = g.reshape(img.shape)

plt.subplot(1,2,1)
plt.axis('off')
plt.title('Equalized Img')
plt.imshow(g, cmap="gray")

ax = plt.subplot(1,2,2)
hist = plt.hist(g)

ax2 = ax.twinx()
plt.title('Histogram and CDF')
ax2.plot(np.cumsum(np.bincount(g.ravel().astype(np.uint8))))


Out[5]:
[<matplotlib.lines.Line2D at 0x7f5e57e66990>]

Adequação de imagem a histograma Genérico


In [6]:
hout = np.concatenate((np.arange(128),np.arange(128,0,-1)))
hcc1 = normalize(np.cumsum(hout), (0, img.size))
# histogram that represents the same number of pixels from
# the original image
h1 = np.diff(np.concatenate(([0], hcc1)))

plt.subplot(1,3,1)
plt.title('original')
plt.plot(hout)

plt.subplot(1,3,2)
plt.plot(hcc1)

plt.subplot(1,3,3)
plt.plot(h1)


gs = np.repeat(np.arange(len(h1)), h1).astype(np.uint8)

# mapear os pixels ordenados da original para os pixels
# ditados pelo nosso histograma dado

g = np.empty((img.size,), np.uint8)
si = np.argsort(img.ravel())
g[si] = gs
g = g.reshape(img.shape)

plt.imshow(g, cmap="gray")


Out[6]:
<matplotlib.image.AxesImage at 0x7f5e568bcd90>

In [6]:


In [6]: